package coop.bancocredicoop.proyectos.gd.service;

import java.util.Date;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Query;
import org.hibernate.Transaction;
import org.hibernate.classic.Session;

import coop.bancocredicoop.proyectos.gd.DocumentFile;
import coop.bancocredicoop.proyectos.gd.GDConfig;
import coop.bancocredicoop.proyectos.gd.SourceDocument;
import coop.bancocredicoop.proyectos.gd.Usuario;
import coop.bancocredicoop.proyectos.gd.alfresco.AlfrescoHttpClient;
import coop.bancocredicoop.proyectos.gd.alfresco.Utils;
import coop.bancocredicoop.proyectos.gd.alfresco.WebScriptResultWithVersion;
import coop.bancocredicoop.proyectos.gd.crecerxxi.CrecerXXIWrapperFactory;
import coop.bancocredicoop.proyectos.gd.domain.Box;
import coop.bancocredicoop.proyectos.gd.domain.Customer;
import coop.bancocredicoop.proyectos.gd.domain.Document;
import coop.bancocredicoop.proyectos.gd.domain.DocumentType;
import coop.bancocredicoop.proyectos.gd.fileListing.DocumentBrowser;
import coop.bancocredicoop.proyectos.gd.query.DataService;
import coop.bancocredicoop.proyectos.gd.query.customer.FindCustomerByIdPersona;

public class DocumentService extends DataService {

	private static final Log log = LogFactory.getLog(DocumentService.class);
	
	public Document getPreviousDocument(Customer customer, DocumentType documentType) {
		Session session = getSession();
		Document document = null;
		try {
			Query query = getPreviousDocumentQuery(session, customer, documentType);
			query.setMaxResults(1);
			document = (Document) query.uniqueResult();
		} finally {
			closeSession(session);
		}
		return document;
	}

	private Query getPreviousDocumentQuery(Session session, Customer customer,
			DocumentType documentType) {
		Query query = session.createQuery("from Document where customer = :customer AND documentType = :documentType AND lastVersion = :lastVersion AND deleteDate is null");
		query.setEntity("customer", customer);
		query.setEntity("documentType", documentType);
		query.setBoolean("lastVersion", true);
		return query;
	}
	
	public List<Document> getPreviousDocumentList(Customer customer, DocumentType documentType) {
		Session session = getSession();
		List<Document> documentList = null;
		try {
			Query query = getPreviousDocumentQuery(session, customer, documentType);
			documentList = query.list();
		} finally {
			closeSession(session);
		}
		return documentList;
	}
	
	public Document getDocumentById(Long documentId) {
		Session session = getSession();
		Document document = null;
		try {
			document = (Document) session.get(Document.class, documentId);
		} finally {
			closeSession(session);
		}
		return document;
	}
	
	public boolean needsNewVersionConfirmation(Long idPersona, Long documentTypeId) throws Exception {
		
		Customer customer = null;
		DocumentType documentType = new DocumentTypeService().getById(documentTypeId);
		
		
		if (!documentType.getVersionable()) {
			log.info(String.format("El tipo de documento no es versionable: %s", documentTypeId));
			return false;
		}
		
		try {
			customer = new FindCustomerByIdPersona().run(idPersona);
			if (customer == null) {
				log.info(String.format("El cliente no existe, idPersona: %s",  idPersona));
				return false;
			}
		} catch (Exception e) {
			log.error(String.format("Error al querer obtener el cliente, idPersona: %s", idPersona), e);
			throw e;
		}
		
		Document prevDocument = getPreviousDocument(customer, documentType);
		if (prevDocument != null) {
			log.info(String.format("Existe una version anterior del documento: %s, %s: %s", customer.getIdPersona(), documentType.getId(), prevDocument.getId()));
			return true;
		} else {
			return false;
		}
		
	}
	
    public String getDocumentName(Customer customer, DocumentType documentType) throws Exception {
        
    	if (documentType.getVersionable()) {
            return String.format("%s.pdf", documentType.getShortName());
        } else {
        	List<Document> prevDocuments = getPreviousDocumentList(customer, documentType);
            int nextDocumentNumber = prevDocuments.size() + 1;
            return String.format(String.format("%s-%03d.pdf", documentType.getShortName(), nextDocumentNumber));
        }

    }
	
    private Document getCurrentVersion(Customer customer, DocumentType documentType) {
		
		if (documentType.getVersionable()) {
			return getPreviousDocument(customer, documentType);
		} else {
			return null;
		}
	}
	
	public Document createDocument(Session session, 
								   String documentName, 
								   Customer customer,
								   Box box,
								   DocumentType documentType,
								   Date validTo,
								   String tags,
								   boolean islastVersion,
								   Usuario createdByUser,
								   Date createdDate,
								   String notes,
								   String documentVersion,
								   Long realVersion) {
		
		Document newDocument = new Document();
		newDocument.setVersion(1L); // Used for concurrent updates, ignored for now
		newDocument.setDocumentVersion(documentVersion);
		newDocument.setName(documentName);
		newDocument.setCustomer(customer);
		newDocument.setBox(box);
		newDocument.setDocumentType(documentType);
		newDocument.setValidTo(validTo);
		newDocument.setTags(tags);
		newDocument.setLastVersion(islastVersion);
		newDocument.setCreatedByUserName(createdByUser.getUserName());
		newDocument.setCreatedDate(createdDate);
		newDocument.setNotes(notes);
		newDocument.setRealVersion(realVersion);	
		newDocument.setLastUpdated(createdDate);
		session.save(newDocument);
		return newDocument;
	
	}
	
    private void invalidatePreviousVersions(Session session, Document document) {
        if (document.getDocumentType().getVersionable()) {

    		Query query = session.createQuery("UPDATE Document set lastVersion = false, lastUpdated = :lastUpdated where customer = :customer AND documentType = :documentType AND lastVersion = :lastVersion");
    		query.setEntity("customer", document.getCustomer());
			query.setEntity("documentType", document.getDocumentType());
    		query.setBoolean("lastVersion", true);
    		query.setTimestamp("lastUpdated", document.getLastUpdated());

    		int affected = query.executeUpdate();
    		log.info(String.format("%s documentos de tipo %s fueron deprecados para el cliente: %s", affected, document.getDocumentType().getId(), document.getCustomer().getId()));
        }
    }
    
	public DocumentCreationResult createDocument(Long idPersona, String cajaId, Long documentTypeId, Date expirationDate, String tags, SourceDocument documentFile, Usuario loggedInUser, Date now, String notes, Long realVersion) throws Exception {
		 Session session = getSession();
		 Transaction tx = null;
		 DocumentCreationResult creationResult = null;
		 try {
		     tx = session.beginTransaction();
		     creationResult = createDocument(session, idPersona, cajaId, documentTypeId, expirationDate, tags, documentFile, loggedInUser, now, notes, realVersion);
		     tx.commit();
		 }
		 catch (Exception e) {
			 rollback(tx);
		     throw e;
		 }
		 finally {
			 closeSession(session);
		 }
		 return creationResult;
		 
	}
	
	private DocumentCreationResult createDocument(Session session, Long idPersona, String cajaId, Long documentTypeId, Date expirationDate, String tags, SourceDocument documentFile, Usuario loggedInUser, Date now, String notes, Long realVersion) throws Exception {

        DocumentType documentType = new DocumentTypeService().getById(documentTypeId);
        Customer customer = null;
        
        try {
			customer = new CrecerXXIWrapperFactory().getCrecerXXIWrapper().findOrCreateCustomer(idPersona);
		} catch (Exception e) {
			String errorMessage = String.format("El cliente no se pudo obtener desde Crecer XXI: %s", idPersona);
			log.error(errorMessage, e);
			throw new RuntimeException(errorMessage);
		}
        
        String documentName = getDocumentName(customer, documentType);
        Box box = new BoxService().getOrCreateBox(session, cajaId);
        Document currentVersion = getCurrentVersion(customer, documentType);

        if (realVersion == null) {
        	realVersion = currentVersion != null && currentVersion.getDeleteDate() == null ? currentVersion.getRealVersion() + 1 : 1;
        }
        
        Document document = createDocument(session,
        		documentName, 
				customer,
				box,
				documentType,
				expirationDate,
				tags,
				true,
				loggedInUser,
				now,
				notes,
				"0.0",
				realVersion);
        
        invalidatePreviousVersions(session, document); 
        AlfrescoHttpClient client = Utils.getAlfrescoClientFromConfigAsUser(loggedInUser.getUserName());
        WebScriptResultWithVersion result = client.uploadFile(documentName, document, documentFile.getInputStream());

        if (result.isSuccessful()) {
            document.setDocumentVersion(result.getData().getVersion().getLabel());
            session.save(document);
            // TODO: sendUploadNotification(document);
        } else {
            throw new RuntimeException(result.getMessage()); 
        }

        new DocumentBrowser(new GDConfig().getGrupoDocumentalIIConfig().getRepositoryPath())
        	.notifyUpload(documentFile);
        
       	return new DocumentCreationResult(result, document);
       	
	}
	
}

